package org.swxjava.explorer;

import java.beans.Introspector;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.swxjava.WebContext;
import org.swxjava.WebContextFactory;
import org.swxjava.core.ServiceLocatorManager;
import org.swxjava.locator.ServiceLocator;
import org.swxjava.util.Log;
import org.swxjava.util.LogFactory;

public class DiscoveryService {

	/** Logger */
	private static final Log LOG = LogFactory.getLog(DiscoveryService.class);

	/** OmitMethods */
	private static final Map<String, Object> OMIT_METHODS = new HashMap();

	static {
		for (Method m : Object.class.getMethods()) {
			if (m != null) {
				LOG.debug("Omit service method : " + m.getName());
				OMIT_METHODS.put(m.getName(), true);
			}
		}
	}

	public DiscoveryService() {
	}

	/**
	 * Get the list of services
	 * 
	 * @returns An array of array ready to be bound to a Tree
	 */
	public List getServices() {
		List serviceNames = getServiceLocator().getServiceNames();
		List services = new ArrayList();
		for (Iterator it = serviceNames.iterator(); it.hasNext();) {
			services.add(createServiceItem(String.valueOf(it.next())));
		}
		return services;
	}

	private Map createServiceItem(String name) {
		Map item = new HashMap();
		item.put("label", name);
		item.put("data", "");
		return item;
	}

	/**
	 * Describe a service and all its methods
	 * 
	 * @param data
	 *            An object containing 'label' and 'data' keys
	 */
	public Map describeService(Map data) throws Exception {
		if (data == null) {
			throw new IllegalArgumentException("Data was null");
		}
		Map methods = new HashMap();
		String serviceName = (String) data.get("label");

		ServiceLocatorManager locatorManager = getServiceLocator();
		ServiceLocator locator = locatorManager.getServiceLocator(serviceName);

		Class serviceClass = locator.getInstance().getClass();
		Method[] serviceMethods = serviceClass.getMethods();
		for (int i = 0; i < serviceMethods.length; i++) {
			Method method = serviceMethods[i];
			if (!OMIT_METHODS.containsKey(method.getName())) {
				Map methodDesc = new HashMap();
				List args = new ArrayList();
				for (int j = 0; j < method.getParameterTypes().length; j++) {
					Class c = method.getParameterTypes()[j];
					args.add(Introspector.decapitalize(c.getSimpleName()));
				}
				methodDesc.put("arguments", args);
				// methodDesc.put("access", method.getModifier())
				methods.put(method.getName(), methodDesc);
			}
		}
		return methods;
	}

	private ServiceLocatorManager getServiceLocator() {
		WebContext context = WebContextFactory.get();
		ServiceLocatorManager locatorManager = context.getContainer().getServiceLocatorManager();
		return locatorManager;
	}
}
